import {
	ConvexObjectBreaker
} from 'three/examples/jsm/misc/ConvexObjectBreaker.js';

const convexBreaker = new ConvexObjectBreaker();

function jieChuJianCe(scene, physicsAddMesh, physicsSetMeshPosition, yiChuWuTi, physicsDispatcher, physicsMeshes, jueSeWo, ws, danHen) {

	const impactPoint = new THREE.Vector3();
	const impactNormal = new THREE.Vector3();
	const objectsToRemove = [];
	let numObjectsToRemove = 0;

	//快速物体射线碰撞检测
	for (let s = 0; s < physicsMeshes.length; s++) {
		let mesh = physicsMeshes[s];
		if (mesh.userData.kuaiSuWuTi) {

			let raycaster;
			let direction = new THREE.Vector3();

			let shangCiWeiZhi = new THREE.Vector3().copy(mesh.userData.shangCiWeiZhi);
			let benCiWeiZhi = new THREE.Vector3().copy(mesh.position);

			direction.subVectors(benCiWeiZhi, shangCiWeiZhi).normalize();
			
			let lookPosition = benCiWeiZhi.addScaledVector(direction, 1);
			mesh.lookAt(lookPosition);//调整飞行物的姿势方向
			
			let margin = 0.05;//bullet碰撞边缘
			let bulletTiQianLiang = mesh.userData.suDu / 60;//bullet可能会预测下帧而提前碰撞
			
			raycaster = new THREE.Raycaster(shangCiWeiZhi, direction, 0, Infinity);

			let intersects = raycaster.intersectObjects(physicsMeshes);

			for (let i = 0; i < intersects.length; i++) {
				
				let yuCeJuLiVec3 = new THREE.Vector3().subVectors(benCiWeiZhi, intersects[i].point);
				let mianVec3 = yuCeJuLiVec3.clone().projectOnPlane(intersects[i].face.normal);
				let chuiZhiJuli = Math.sqrt(yuCeJuLiVec3.lengthSq() - mianVec3.lengthSq());
				if (chuiZhiJuli > margin * 3 + bulletTiQianLiang + mesh.userData.changDu / 2) break;//本次位置小于bullet碰撞检测范围 再检测
				
				let beiDajiObj = intersects[i].object;
				let name = beiDajiObj.name;

				if (!name.includes('bao')) {

					//攻击玩家角色
					//射线检测不到绑定动画的mesh
					if (!!beiDajiObj.userData.jueSeHao && beiDajiObj.userData.jueSeHao != jueSeWo.userData.jueSeHao && name.includes('pengZhuang')) {

						jueSeWo.userData.woDaJi = {
							jueSeHao: beiDajiObj.userData.jueSeHao,
							shangHai: 50
						}
						//给服务端发送信息
						let jueSeJson = {
							jueSeHao: jueSeWo.userData.jueSeHao,
							weiZhi: {x: jueSeWo.position.x, y: jueSeWo.position.y, z: jueSeWo.position.z},
							xuanZhuan: {x: jueSeWo.quaternion.x, y: jueSeWo.quaternion.y, z: jueSeWo.quaternion.z, w: jueSeWo.quaternion.w},
							dongZuo: jueSeWo.userData.dongZuo.zhuangTai,
							woDaJi: jueSeWo.userData.woDaJi
						}
						ws.send(JSON.stringify(jueSeJson));
						
						jueSeWo.userData.woDaJi = undefined;
						yiChuWuTi(mesh);
						
						mesh.layers.set(0);
						mesh.position.copy(shangCiWeiZhi);
						mesh.lookAt(benCiWeiZhi);
						mesh.position.copy(intersects[i].point);
						beiDajiObj.parent.attach(mesh);

						break;
					}
					
					//破碎
					if (name.includes('sui')) {
						const debris = convexBreaker.subdivideByImpact(beiDajiObj, intersects[i].point, intersects[i]
							.face.normal, 1, 2);
					
						const numObjects = debris.length;
						for (let j = 0; j < numObjects; j++) {
					
							const vel = mesh.userData.physicsBody.getLinearVelocity();
							const angVel = mesh.userData.physicsBody.getAngularVelocity();
							const fragment = debris[j];
							fragment.userData.velocity.set(vel.x(), vel.y(), vel.z());
							fragment.userData.angularVelocity.set(angVel.x(), angVel.y(), angVel.z());
					
							fragment.name = 'sui'
							fragment.castShadow = true;
							fragment.receiveShadow = true;
							scene.add(fragment)
							physicsAddMesh(fragment);
							yiChuWuTi(beiDajiObj);
							yiChuWuTi(mesh);
						}
						break;
					}
					
					//滚动物体
					if (beiDajiObj.parent.name.includes('dong') && !beiDajiObj.userData.jueSeHao) {
						
						mesh.position.copy(intersects[i].point);
						physicsSetMeshPosition(mesh, intersects[i].point);
						break;
					}

					//弹痕
					if (((name.includes('xianShi') || beiDajiObj.parent.name.indexOf('xianShi') > -1)) ) {
						
						const geometry = new THREE.CircleGeometry(0.05, 32);
						
						const texture = danHen;
						texture.wrapS = THREE.RepeatWrapping;
						texture.wrapT = THREE.RepeatWrapping;
						texture.repeat.set( 1, 1 );
						const material = new THREE.MeshBasicMaterial( { map: texture } );
						material.transparent = true;
						
						const plane = new THREE.Mesh(geometry, material);
						plane.lookAt(intersects[i].face.normal);
						plane.position.copy(intersects[i].point);
						plane.position.addScaledVector(intersects[i].face.normal, 0.001);
						beiDajiObj.attach(plane);
						yiChuWuTi(mesh);
						
						mesh.layers.set(0);//只剩 层0
						mesh.position.copy(shangCiWeiZhi);
						mesh.lookAt(benCiWeiZhi);
						mesh.position.copy(intersects[i].point);
						scene.add(mesh);

						break;
					}

				}

			}
		}
	}

	for (let i = 0, il = physicsDispatcher.getNumManifolds(); i < il; i++) {

		const contactManifold = physicsDispatcher.getManifoldByIndexInternal(i);
		const rb0 = Ammo.castObject(contactManifold.getBody0(), Ammo.btRigidBody);
		const rb1 = Ammo.castObject(contactManifold.getBody1(), Ammo.btRigidBody);

		const threeObject0 = Ammo.castObject(rb0.getUserPointer(), Ammo.btVector3).threeObject;
		const threeObject1 = Ammo.castObject(rb1.getUserPointer(), Ammo.btVector3).threeObject;

		if (!threeObject0 && !threeObject1) {

			continue;

		}

		const userData0 = threeObject0 ? threeObject0.userData : null;
		const userData1 = threeObject1 ? threeObject1.userData : null;

		const breakable0 = userData0 ? userData0.breakable : false;
		const breakable1 = userData1 ? userData1.breakable : false;

		const collided0 = userData0 ? userData0.collided : false;
		const collided1 = userData1 ? userData1.collided : false;

		if (!((!breakable0 && !breakable1) || (collided0 && collided1))) {

			let contact = false;
			let maxImpulse = 0;
			for (let j = 0, jl = contactManifold.getNumContacts(); j < jl; j++) {

				const contactPoint = contactManifold.getContactPoint(j);

				if (contactPoint.getDistance() < 0) {

					contact = true;
					const impulse = contactPoint.getAppliedImpulse();

					if (impulse > maxImpulse) {

						maxImpulse = impulse;
						const pos = contactPoint.get_m_positionWorldOnB();
						const normal = contactPoint.get_m_normalWorldOnB();
						impactPoint.set(pos.x(), pos.y(), pos.z());
						impactNormal.set(normal.x(), normal.y(), normal.z());

					}

					break;

				}

			}

			// If no point has contact, abort
			if (!contact) continue;

			// Subdivision

			const fractureImpulse = 250;

			if (breakable0 && !collided0 && maxImpulse > fractureImpulse) {

				const debris = convexBreaker.subdivideByImpact(threeObject0, impactPoint, impactNormal, 1, 2,
					1.5);

				const numObjects = debris.length;
				for (let j = 0; j < numObjects; j++) {

					const vel = rb0.getLinearVelocity();
					const angVel = rb0.getAngularVelocity();
					const fragment = debris[j];
					fragment.userData.velocity.set(vel.x(), vel.y(), vel.z());
					fragment.userData.angularVelocity.set(angVel.x(), angVel.y(), angVel.z());

					fragment.castShadow = true;
					fragment.receiveShadow = true;
					scene.add(fragment)
					physicsAddMesh(fragment);

				}
				//等所有检测完移除破碎父体
				objectsToRemove[numObjectsToRemove++] = threeObject0;

				userData0.collided = true;

			}

			if (breakable1 && !collided1 && maxImpulse > fractureImpulse) {

				const debris = convexBreaker.subdivideByImpact(threeObject1, impactPoint, impactNormal, 1, 2,
					1.5);

				const numObjects = debris.length;
				for (let j = 0; j < numObjects; j++) {

					const vel = rb1.getLinearVelocity();
					const angVel = rb1.getAngularVelocity();
					const fragment = debris[j];
					fragment.userData.velocity.set(vel.x(), vel.y(), vel.z());
					fragment.userData.angularVelocity.set(angVel.x(), angVel.y(), angVel.z());

					fragment.castShadow = true;
					fragment.receiveShadow = true;
					scene.add(fragment);
					physicsAddMesh(fragment);
				}

				objectsToRemove[numObjectsToRemove++] = threeObject1;

				userData1.collided = true;
			}

		}

		//跳越判定
		let jueSe = threeObject0.userData.wo ? threeObject0 : threeObject1.userData.wo ? threeObject1 : false;

		if (jueSe) {
			for (let j = 0, jl = contactManifold.getNumContacts(); j < jl; j++) {
				const contactPoint = contactManifold.getContactPoint(j);

				if (contactPoint.getDistance().toFixed(2) <= 0) {

					let pos = contactPoint.get_m_positionWorldOnB()

					if ((jueSe.position.y - 0.71) > pos.y()) {
						jueSe.userData.keTiao = true;
					}
					break;

				}

			}
		}

		//快速物体
		let kuaiSuWuTi = threeObject0.userData.kuaiSuWuTi ? threeObject0 : threeObject1.userData.kuaiSuWuTi ?
			threeObject1 : false;

		if (kuaiSuWuTi) {

			for (let j = 0, jl = contactManifold.getNumContacts(); j < jl; j++) {
				const contactPoint = contactManifold.getContactPoint(j);

				if (contactPoint.getDistance() < 0) {
					objectsToRemove[numObjectsToRemove++] = kuaiSuWuTi;
					break;
				}

			}
		}

	}
	for (let i = 0; i < numObjectsToRemove; i++) {

		yiChuWuTi(objectsToRemove[i]);

	}

	numObjectsToRemove = 0;
}

export default jieChuJianCe;
